/* 
 * File:   SocketAsincronico.cpp
 * Author: max
 * 
 * Created on June 1, 2013, 9:07 AM
 */

#include "client_SocketAsincronico.h"
#include "common_Codec.h"
#include "common_MutexScopeLocker.h"
#include <string.h>

using namespace TP;
using namespace TP::Comunicacion;

SocketAsincronico::SocketAsincronico (const string& pIp, const string& pPuerto){
    _socket = new Socket(pIp, pPuerto);
    _transmitiendo = false;
}

SocketAsincronico::SocketAsincronico (const string& pIp, const string& pPuerto, const int &pTimeout){
    _socket = new Socket(pIp, pPuerto, pTimeout);
    _transmitiendo = false;
}

SocketAsincronico::~SocketAsincronico (){
    
    delete _socket;
    
    while (!bufferIn().empty())
    {
        bufferIn().pop();
    }

    while (!bufferOut().empty())
    {
        bufferOut().pop();
    }
}

void SocketAsincronico::Iniciar() throw (Excepcion&){
    try
    {
        _socket->Iniciar();
        SetTransmitiendo(true);
        
        Thread::Iniciar();
    }
    catch (Excepcion &ex)
    {
        throw;
    }
}

void SocketAsincronico::Finalizar() throw (Excepcion&){
    try
    {
//        SetTransmitiendo(true);
//        _socket->Finalizar();
//        
//        Thread::Finalizar();
    }
    catch (Excepcion &ex)
    {
        throw;
    }
}

int SocketAsincronico::Escribir(const uint8_t* pMensaje, const size_t pLongitud) throw (Excepcion&){
    
    // Codifica el mensaje (mediante codec.)
    string* mensaje = new string();
    Codec codec;
    codec.codificar(*mensaje, pMensaje, pLongitud);
    
    // Agrega el mensaje a la cola de densajes entrantes para su posterior envio.
    bufferIn().push(mensaje);
}

int SocketAsincronico::Leer (uint8_t* &pMensaje, uint32_t &pLongitud) throw (Excepcion&){
    
    if (bufferOut().size() > 0)
    {
        // Se extrae el primer mensaje de la cola. Se lo decodifica y se lo ubica en pMensaje.
        Codec codec;
        codec.decodificar(pMensaje, pLongitud, *(bufferOut().front()));

        // Desencola el mensaje de la cola y lo elimina.
        delete bufferOut().front();
        bufferOut().pop();
    }
    else
    {
        pMensaje = NULL;
        pLongitud = 0;
    }
}

void SocketAsincronico::tarea (){
    
    while (GetTransmitiendo())
    {
        try
        {
            // Se toma un mensaje de la cola de mensaje a enviar y se lo envia por el socket.
            if (!bufferIn().empty())
            {
                _socket->Escribir(*(bufferIn().front()));
                delete bufferIn().front();
                bufferIn().pop();
            }
            else
            {
                _socket->Escribir("KAKAKA");
            }

            // Se lee un menesaje desde el socket y se lo encola en la cola de mensajes saliente.
            string* mensaje = new string();
            _socket->Leer(*mensaje);
            if (strcmp ("KAKAKA",mensaje->c_str()) != 0)
            {
                bufferOut().push(mensaje);
            }
        }
        catch (Excepcion &ex)
        {
            cerr << ex.what() << endl;
            SetTransmitiendo(false);
        }
    }
}

queue<string*>& SocketAsincronico::bufferIn(){
    MutexScopeLocker locker (_mutexBufferIn);
    return _bufferIn;
}

queue<string*>& SocketAsincronico::bufferOut(){
    MutexScopeLocker locker (_mutexBufferOut);
    return _bufferOut;
}

bool SocketAsincronico::GetTransmitiendo(){
    MutexScopeLocker _locker (_mutexTransmitiendo);
    return _transmitiendo;
}

bool SocketAsincronico::SetTransmitiendo(bool pValor){
    MutexScopeLocker _locker (_mutexTransmitiendo);
    return _transmitiendo = pValor;

}